package com.maiko.maikoaiagent.advisor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.advisor.api.*;
import org.springframework.ai.chat.model.MessageAggregator;
import reactor.core.publisher.Flux;

/**
 * 自定义日志 Advisor：为什么要搞一个自定义Advisor呢？因为Spring AI虽然内置了SimpleLoggerAdvisor日志拦截器，但是它是以
 * Debug级别输出日志，而默认SpringBoot项目的日志级别是Info级别，所以你看不到打印的日志信息。
 * | 级别      | 名称 | 说明                       | 适合场景示例                        |
 * | ------- | -- | ------------------------ | ----------------------------- |
 * | `ERROR` | 错误 | 表示严重错误，程序可能无法继续运行        | 数据库连接失败、空指针异常、系统不可恢复性错误等      |
 * | `WARN`  | 警告 | 表示可能存在风险，但程序还能正常运行       | 接口响应时间过长、使用了过时的 API           |
 * | `INFO`  | 信息 | 正常的、重要的运行信息，表示程序正在做什么    | 用户登录成功、服务启动完成、任务处理成功等         |
 * | `DEBUG` | 调试 | 用于开发调试阶段的详细信息，不建议在生产环境开启 | 打印变量值、进入方法、SQL 语句参数、业务分支判断信息等 |
 * | `TRACE` | 跟踪 | 更加详细的调试信息，用于追踪程序的每一步执行流程 | 方法进入/退出、循环内部细节、低级别运行细节        |
 *
 * 所以你要去application.yml中配置日志级别为debug
 * logging:
 *   level:
 *     org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor: debug
 * 但是你这样不够优雅，其他同学想看拦截器的时候每次都要看那么多的内容，要自己指定日志级别
 *
 *
 * 思路：
 * 它这个是怎么来的呢，你自己写是不是一头雾水？你别自己去想，这个东西你去看源码，直接把SimpleLoggerAdvisor拉过来
 * 然后对着SimpleLoggerAdvisor改即可。
 *
 *
 * 这段代码是一个典型的 拦截器模式（Interceptor Pattern）的实现，用于对某种“调用请求-响应”流程（如 AI 服务请求）
 * 做前置处理（Before） 和后置观察（After），适用于同步和流式调用。
 * 打印 info 级别日志、只输出单次用户提示词和 AI 回复的文本
 */
@Slf4j
public class MyLoggerAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {

    /**
     * 返回当前类的简单类名，可能用于注册或日志标识。
     * @return
     */
    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }

    /**
     * 返回拦截器的顺序，数字越小优先级越高。用于多个拦截器时排序执行。
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 这是一个前置处理函数，在请求发出之前打印日志：
     * request.userText() 可能是用户发送的原始请求文本。
     * 这个方法不会修改请求，只是记录日志。
     * @param request
     * @return
     */
    private AdvisedRequest before(AdvisedRequest request) {
        log.info("AI Request: {}", request.userText());
        return request;
    }

    /**
     * 这是一个后置观察函数，在响应返回之后记录日志：
     * advisedResponse.response() 得到实际响应对象
     * .getResult().getOutput().getText() 获取最终的输出文本
     * @param advisedResponse
     */
    private void observeAfter(AdvisedResponse advisedResponse) {
        log.info("AI Response: {}", advisedResponse.response().getResult().getOutput().getText());
    }

    /**
     * 这是同步调用的拦截入口。
     * 流程：
     * 调用 before() 打印请求日志。
     * 调用下一个拦截器或目标方法 chain.nextAroundCall(...)。
     * 调用 observeAfter() 打印响应日志。
     * 返回结果。
     */
    public AdvisedResponse aroundCall(AdvisedRequest advisedRequest, CallAroundAdvisorChain chain) {
        advisedRequest = this.before(advisedRequest);
        AdvisedResponse advisedResponse = chain.nextAroundCall(advisedRequest);
        this.observeAfter(advisedResponse);
        return advisedResponse;
    }

    /**
     * 用于异步流式调用（基于 Reactor 的 Flux）的拦截。
     * 流程：
     * 打印请求日志（前置）。
     * 执行链上的下一个流式调用。
     * 使用 MessageAggregator.aggregateAdvisedResponse(...) 聚合响应流，并在每次响应中调用 observeAfter() 打印响应日志。
     */
    public Flux<AdvisedResponse> aroundStream(AdvisedRequest advisedRequest, StreamAroundAdvisorChain chain) {
        advisedRequest = this.before(advisedRequest);
        Flux<AdvisedResponse> advisedResponses = chain.nextAroundStream(advisedRequest);
        return (new MessageAggregator()).aggregateAdvisedResponse(advisedResponses, this::observeAfter);
    }
}
